package com.hyzh.latte.vehicle.nezha;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.coffee.concurrent.CoffeeExecutorManager;
import com.hyzh.latte.sandtable.pojo.PointData;
import com.hyzh.latte.sandtable.service.GeoQueryService;
import com.hyzh.latte.vehicle.dmo.VehicleBO;
import com.hyzh.latte.vehicle.dmo.VehicleInfo;
import com.hyzh.latte.vehicle.dmo.VehicleListMessage;
import com.hyzh.latte.vehicle.dmo.VehiclePointMessage;
import com.hyzh.latte.vehicle.dmo.entity.PolePGEntity;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author songkui
 * @since 2024/7/6 15:47
 */
@Component
@Slf4j
@AllArgsConstructor
public class VehicleScheduledTask {

    private final GeoQueryService geoQueryService;

    @Scheduled(initialDelay = 5 * 1000, fixedRate = 5000)
    public void executeTask() {

        ParkDeviceBuilder builder = NezhaDeviceManager.getInstance().getBuilderData();
        List<String> parkList = builder.getParkMap();
        CoffeeExecutorManager.getInstance().getDefaultExecutor().execute(() -> {
            for (String park : parkList) {
                doTask(park);
            }
        });
    }

    @Scheduled(initialDelay = 2 * 1500, fixedRate = 2000)
    public void executeTaskList() {

        ParkDeviceBuilder builder = NezhaDeviceManager.getInstance().getBuilderData();
        List<String> parkList = builder.getParkMap();
        CoffeeExecutorManager.getInstance().getDefaultExecutor().execute(() -> {
            for (String park : parkList) {
                doTaskPoint(park);
            }
        });
    }

    private void doTaskPoint(String park) {
        Set<NezhaClient> clientSet = NezhaSessionManager.getInstance().setClientByParkCode(park);
        if (CollectionUtil.isEmpty(clientSet)) {
            log.info("VehicleScheduledTask send point msg clientSet is null");
            return;
        }
        VehicleCache vehicleCache = VehicleManager.getInstance().vehicleCache(park);
        if (null == vehicleCache || vehicleCache.size() == 0) {
            log.info("VehicleScheduledTask send point msg vehicleCache is null");
            return;
        }

        Map<String, PolePGEntity> poleMap = NezhaDeviceManager.getInstance().getBuilderData().getPoleEntityMap().get(park);
        if (CollectionUtil.isEmpty(poleMap)) {
            log.info("VehicleScheduledTask send point msg poleMap is null");
            return;
        }

        Map<String, VehicleBO> map = vehicleCache.getAllEntries(); //车辆信息
        if (CollectionUtil.isEmpty(map)) {
            log.info("VehicleScheduledTask send point msg VehicleBO map is null");
            return;
        }

        //
        List<VehicleInfo> listData = new ArrayList<>();
        int pn = 0;
        for (VehicleBO vehicleBO : map.values()) {
            Optional.ofNullable(vehicleInfo(park, vehicleBO, pn)).ifPresent(listData::add);
            ++pn;
        }
        //理合
        List<PointData> listPD = listData.stream().map(v -> new PointData(Double.parseDouble(v.getLat()), Double.parseDouble(v.getLon()), Double.parseDouble(v.getHeight()), v.getPointNo(), 0)).collect(Collectors.toList());
        List<PointData> resList = geoQueryService.pointFitToRoads(listPD, park);
        if (CollectionUtil.isEmpty(resList)) {
            log.error("do LiXin api: is null");
            return;
        }

        VehiclePointMessage message = new VehiclePointMessage();
        message.setData(resList);
        log.info("VehicleScheduledTask send point msg: size: {}", message.getData().size());
        for (NezhaClient client : clientSet) {
            client.sendVehiclePointMsg(message);
        }

    }


    private void doTask(String park) {
        Set<NezhaClient> clientSet = NezhaSessionManager.getInstance().setClientByParkCode(park);
        if (CollectionUtil.isEmpty(clientSet)) {
            log.info("VehicleScheduledTask send msg: clientSet is null");
            return;
        }
        VehicleCache vehicleCache = VehicleManager.getInstance().vehicleCache(park);
        if (null == vehicleCache || vehicleCache.size() == 0) {
            log.info("VehicleScheduledTask send msg: vehicleCache is null");
            return;
        }

        Map<String, PolePGEntity> poleMap = NezhaDeviceManager.getInstance().getBuilderData().getPoleEntityMap().get(park);
        if (CollectionUtil.isEmpty(poleMap)) {
            log.info("VehicleScheduledTask send msg: poleMap is null");
            return;
        }

        Map<String, VehicleBO> map = vehicleCache.getAllEntries(); //车辆信息
        if (CollectionUtil.isEmpty(map)) {
            log.info("VehicleScheduledTask send msg: VehicleBO MAP is null");
            return;
        }

        //
        Map<String, List<VehicleInfo>> data = new HashMap<>();
        List<VehicleInfo> listData = new ArrayList<>();
        int pn = 0;
        for (VehicleBO vehicleBO : map.values()) {
            String road = Optional.ofNullable(poleMap.get(vehicleBO.getCurrentPole().getPoleCode())).map(PolePGEntity::getRoad).orElse("其他");
            List<VehicleInfo> list = data.computeIfAbsent(road, v -> new ArrayList<>());
            Optional.ofNullable(vehicleInfo(park, vehicleBO, pn)).ifPresent(x -> {
                listData.add(x);
                list.add(x);
            });
            ++pn;
        }

        //理合
        List<PointData> listPD = listData.stream().map(v -> new PointData(Double.parseDouble(v.getLat()), Double.parseDouble(v.getLon()), Double.parseDouble(v.getHeight()), v.getPointNo(), 0)).collect(Collectors.toList());
        List<PointData> resList = geoQueryService.pointFitToRoads(listPD, park);
        if (CollectionUtil.isNotEmpty(resList)) {
            Map<Integer, VehicleInfo> m = listData.stream().collect(Collectors.toMap(VehicleInfo::getPointNo, Function.identity()));
            for (PointData pd : resList) {
                Optional.ofNullable(m.get(pd.getPointNo())).ifPresent(x -> x.updatePoint(String.valueOf(pd.getLon()), String.valueOf(pd.getLat()), String.valueOf(pd.getHeight()), pd.getIndex()));
            }
        } else {
            log.error("do LiXin api: is null");
        }

        VehicleListMessage message = new VehicleListMessage();
        message.setData(data);
        log.info("VehicleScheduledTask send msg: size: {}", message.getData().size());
        for (NezhaClient client : clientSet) {
            client.sendVehicleListMsg(message);
        }

    }

    public VehicleInfo vehicleInfo(String park, VehicleBO vehicleBO, int pn) {
        PolePGEntity pgEntity = NezhaDeviceManager.getInstance().getPolePGEntityByPoleCode(park, vehicleBO.getCurrentPole().getPoleCode());
        if (null == pgEntity) {
            return null;
        }

        String lon = StrUtil.isNotEmpty(pgEntity.getXLon()) ? pgEntity.getXLon() : pgEntity.getYLon();
        String lat = StrUtil.isNotEmpty(pgEntity.getXLat()) ? pgEntity.getXLat() : pgEntity.getYLat();
        String h = StrUtil.isNotEmpty(pgEntity.getXHeight()) ? pgEntity.getXHeight() : pgEntity.getYHeight();

        return new VehicleInfo(vehicleBO.getVehicleNo(), vehicleBO.getType(), lon, lat, h, pn, 0);
    }

}

